package com.hh.game.service.gateway.manager.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hh.game.service.gateway.manager.service.config.ConfigResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;
import java.util.Set;

public class LoadServiceConfigForJson implements LoadServiceConfig {
    private static Logger log = LoggerFactory.getLogger(ServiceConfigManager.class);

    @Override
    public Set<ServiceRouteVo> load(ConfigResource resource, Object oldData) throws Exception {
        Set<ServiceRouteVo> result = new HashSet<>();

        String jsonData = (String) resource.getData();

        JSONObject json = JSON.parseObject(jsonData);

        String serviceName = json.getString("name");
        JSONArray arr = json.getJSONArray("service");

        if (oldData != null) {
            try {
                removeUnuseService(serviceName, arr, JSON.parseObject(oldData.toString()).getJSONArray("service"));
            } catch (Exception e) {
                log.error("remove unUse service error", e);
            }
        }

        CountMethodIndex count = new CountMethodIndex();
        arr.forEach(val -> {
            count.index++;
            JSONObject obj = (JSONObject) val;
            String handler = obj.getString("handler");
            JSONArray methods = obj.getJSONArray("method");
            methods.forEach(tmp -> {
                try {
                    JSONObject method = (JSONObject) tmp;
                    String methodName = method.getString("name");
                    JSONArray parameterTypes = method.getJSONArray("parameterTypes");
                    String[] parameterTypeArray;
                    if (parameterTypes != null) {
                        parameterTypeArray = new String[parameterTypes.size()];
                        parameterTypes.toArray(parameterTypeArray);
                    } else {
                        parameterTypeArray = new String[0];
                    }
                    JSONArray argsName = method.getJSONArray("argsName");
                    String[] args = null;
                    if (argsName != null && !argsName.isEmpty()) {
                        args = new String[argsName.size()];
                        argsName.toArray(args);
                    } else if (parameterTypeArray.length > 1) {
                        throw new IllegalArgumentException("argsName cannot be null when parameterTypes is not null");
                    }
                    ServiceRouteConfigCache.add(serviceName,
                            ServiceRouteConfigCache.buildMethodSign(handler, methodName),
                            parameterTypeArray, args);
                    result.add(new ServiceRouteVo(serviceName ,handler ,methodName));
                } catch (Exception e) {
                    log.error("parse service config error ,method index [" + count.index + "]", e);
                }
            });
        });
        return result;
    }

    private void removeUnuseService(String serviceName, JSONArray newServices, JSONArray oldServices) {
        Set<String> signs = new HashSet<>();
        newServices.stream()
                .map(service -> (JSONObject) service)
                .forEach(service -> {
                    String handler = service.getString("handler");
                    JSONArray methods = service.getJSONArray("method");
                    methods.stream().map(m -> (JSONObject) m).forEach(m -> {
                        signs.add(ServiceRouteConfigCache.buildMethodSign(handler, m.getString("name")));
                    });
                });
        oldServices.stream()
                .map(service -> (JSONObject) service)
                .forEach(service -> {
                    String handler = service.getString("handler");
                    JSONArray methods = service.getJSONArray("method");
                    methods.stream().map(m -> (JSONObject) m)
                            .map(m -> ServiceRouteConfigCache.buildMethodSign(handler, m.getString("name")))
                            .filter(sign -> !signs.contains(sign))
                            .forEach(sign -> ServiceRouteConfigCache.remove(serviceName, sign));
                });

    }

    static class CountMethodIndex {
        int index = -1;
    }
}
